﻿using Cofe.Core.Property;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;

namespace Cofe.Core.Security
{
    public interface ISecurityManager : ICofeService
    {
        IUserManager UserManager { get; }

        /// <summary>
        /// Or COFEServices.CurrentPrincipal.
        /// </summary>
        IPrincipal CurrentPrincipal { get; set; }

        /// <summary>
        /// Request permission for specified object.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="requestedObj"></param>
        /// <param name="permissionType"></param>
        /// <exception cref="SecurityException">The user principal do not have role to access the object.</exception>
        void DemandPermission<T>(T requestedObj, PermissionType permissionType) where T : IProtectedData<T>;

        /// <summary>
        /// Get whether permission granted, doesnt throw exception.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="?"></param>
        /// <param name="permissionType"></param>
        /// <returns></returns>
        bool IsPermissionGranted<T>(T requestedObj, PermissionType permissionType) where T : IProtectedData<T>;

        /// <summary>
        /// Calls UserManager.GetPrincipal and assign it to CurrentPrincipal.
        /// </summary>
        /// <param name="identity">Identity used to </param>
        void setIdentity(IIdentity identity = null);

        CofeImpersonationContext ImpersonateAs(IIdentity identity);
        CofeImpersonationContext ImpersonateAsService(string serviceType);


        IEnumerable<IPermissionPolicy<T>> GetPermissionPolicies<T>() where T : IProtectedData<T>;
        IEnumerable<IPermissionPolicy> GetPermissionPolicies(Func<IPermissionPolicy, bool> filter);
        void AddPermissionPolicy(IPermissionPolicy policy);
        void RemovePermissionPolicy(Func<IPermissionPolicy, bool> filter);

        /// <summary>
        /// These policies are saved/loaded in settings.
        /// </summary>
        IEnumerable<IPermissionPolicy> PermissionPolicies { get; }

        /// <summary>
        /// Manually registered permission policies thats not saved in settings.
        /// </summary>
        List<IPermissionPolicy> ServicePermissionPolicies { get; }
    }

    public interface IPermissionPolicy
    {
        /// <summary>
        /// Principal that satisfy any of the required role would pass.
        /// </summary>
        string[] RequiredRole { get; }

      
    }

    public interface IPermissionPolicy<T> : IPermissionPolicy where T : IProtectedData
    {
        /// <summary>
        /// Whether this policy applied to the requested object 
        /// </summary>
        /// <param name="objRequested"></param>
        /// <returns></returns>
        bool Match(T requestedObj, PermissionType permissionType); 
    }
}
